package com.example.project4;

//import java.io.BufferedWriter;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
//import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;

import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import android.widget.Toast;

public class ConnectionService extends Service{
	
    static final int CONNECT = 0, LIST = 1, DIFF = 2, PULL = 3, LEAVE = 4, CAP = 5;
    static final String IP_ADDRESS = "10.0.2.2";   //for lovalhost or "130.207.114.21" for shuttle
    static final int PORT_NUMBER = 2005;
    static final int TITLELEN = 150;
    static final int MD5_DIGEST_LENGTH = 16;
    
	public Client clnt = new Client();
	
    
    /**
     * Handler of incoming messages from bond activity.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LIST:
                	clnt.execute(1);
                    Toast.makeText(getBaseContext(), "After List!", Toast.LENGTH_SHORT).show();
                    break;
                case DIFF:
                	clnt.execute(2);
                    Toast.makeText(getBaseContext(), "After diff!", Toast.LENGTH_SHORT).show();
                    break;
                case PULL:
                	clnt.execute(3);
                    Toast.makeText(getBaseContext(), "After pull!", Toast.LENGTH_SHORT).show();
                    break;
                case LEAVE:
                	clnt.execute(4);
                    Toast.makeText(getBaseContext(), "After Leave!", Toast.LENGTH_SHORT).show();
                    break;
                case CAP:
                	clnt.execute(5);
                    Toast.makeText(getBaseContext(), "After cap!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    
    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
    
    /**
     * This handles all the client connections to the server
     * It must be done on the background and NO TOAST can be print here
     */
    private class Client extends AsyncTask<Integer, Void, Socket> {
		private Socket socket;
		OutputStream out;
	    DataOutputStream dos;
	    InputStream in;
        DataInputStream dis;

        public Client() {
            socket = null;
            out= null;
		    dos = null;
		    in = null;
	        dis = null;
        }

        protected Socket doInBackground(Integer... params) {
        	try {
        		if (socket == null) {
	    			InetAddress serverAddr = InetAddress.getByName(IP_ADDRESS);  
	    			socket = new Socket(serverAddr, PORT_NUMBER);
	    			Log.d("Connection: ", "CONNECTED");
        		}
		    } catch (IOException e) {
		    	Log.e("Connection: ", "Failed to connect...");
		    	e.printStackTrace();
	    	}
	    	
	    	switch (params[0]){
	    		case 1:
	    			Header head = new Header(0,0,0);
	    			try{
	    				//send List Request to server
	    				out = socket.getOutputStream(); 
	    			    dos = new DataOutputStream(out);
	    			    dos.write(head.getHeaderByteArray());
	                    out.flush();
	                    //Receive List response with total length for next message and number of songs
	                    byte [] headerBA = new byte[12];
	                    in = socket.getInputStream();
	                    dis = new DataInputStream(in);
	                    dis.read(headerBA);
	                    Header rcvHead = new Header(headerBA);
	                    Log.d("Connection: ", "Received: "+rcvHead.toString());
	                    
	                    //if total length for next message and number of songs are zero then server has no songs
	                    if((rcvHead.getIndexes()==0) && (rcvHead.getLength()==0)){
	                    	System.out.println("There are no songs on the server.\n\n");
	                	} else {
	                		//else receive all songs info from server
		                    Song [] songs = new Song[head.getLength()];
		                    
		                    int sizeSong = (TITLELEN+MD5_DIGEST_LENGTH+4);
		                    int sizeTotalSongs = (TITLELEN+MD5_DIGEST_LENGTH+4)*head.getLength(); 
		                    byte [] songBA = new byte[sizeSong];
		                    byte [] songsBA = new byte[sizeTotalSongs];
		                    in = socket.getInputStream();
		                    dis = new DataInputStream(in);
		                    dis.read(songsBA);	
		                    
		                    int i,j;
		                    for(i = 0; i<head.getLength(); i++){
		                    	for(j = 0; j < sizeTotalSongs ; j++){
		                    		songBA[j] = songsBA[j+(sizeTotalSongs*i)]; 
		                    	}
		                    	songs [i] = new Song(songBA);
		                    }
		                    
		                    for(i = 0; i<head.getLength(); i++){
		                    	System.out.println("Song "+ i + ": "+songs[i].toString());
		                    }
	                	}
	                     
	    			}catch (IOException e) {
	    		    	Log.e("Connection: ", "Failed to send list request...");
	    	    	}
	    			break;
	    		case 2:
	    			Diff();
	    			break;
	    		case 3:
	    			Pull();
	    			break;
	    		case 4:
	    			Leave();
	    			break;
	    		case 5:
	    			Cap();
	    			break;
	    		default: break;
	    		
	    	}
	    	return socket;
        }
        
        public void Diff(){
        	
        }
        
        public void Pull(){
        	
        }
        
        public void Leave(){
        	
        }
        
        public void Cap(){
        	
        }       
    }
}
